/*   Carina
 *   Copyright (C) 2009 2010 2011  Zdravko Velinov
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "settings-dialog.hh"

#include "carina/renderer-base.hh"

#include <QFileDialog>
#include <QMessageBox>

#include <algorithm>

CESettings::CESettings(QWidget* parent)
    :   QDialog(parent)
{
    m_Dialog.setupUi(this);

    string name;
    Carina::RenderingSubsystem tmpRS;
    for(size_t i = 0; i < tmpRS.getLibraryCount(); ++i)
    {
        name = tmpRS.getLibrary(i)->getName();
        m_Dialog.RendererList->addItem(name.c_str());
    }

    m_Dialog.ResourceView->setModel(&m_ResListModel);

    if(m_SettingsFile.load())
    {
        QStringList     resources;
        string          resource,
                        log_file;
        QString         renderer(m_SettingsFile.getRenderer().c_str());
        
        for(int i = 0; i < m_Dialog.RendererList->count(); ++i)
            if(m_Dialog.RendererList->itemText(i) == renderer)
            {
                m_Dialog.RendererList->setCurrentIndex(i);
                break;
            }
        for(size_t i = 0; i < m_SettingsFile.getResourceCount(); ++i)
        {
            resource = m_SettingsFile.getResource(i);
            resources.append(resource.c_str());
        }
        m_ResListModel.insertRows(resources);
        
        if(m_SettingsFile.isDefaultLogFile())
        {
            m_Dialog.DefaultLogCheckBox->setCheckState(Qt::Checked);
            m_Dialog.LogFileEdit->setDisabled(true);
            m_Dialog.LogFileBrowseButton->setDisabled(true);
        }
        else
        {
            Carina::string log_file = m_SettingsFile.getLogFile();
            m_Dialog.LogFileEdit->setText(log_file.c_str());
            m_Dialog.DefaultLogCheckBox->setCheckState(Qt::Unchecked);
            m_Dialog.LogFileEdit->setDisabled(false);
            m_Dialog.LogFileBrowseButton->setDisabled(false);
        }

        QString log_level_name;
        switch(m_SettingsFile.getLogLevel())
        {
        case CE_LOG_INFO: log_level_name = "INFO"; break;
        case CE_LOG_DEBUG: log_level_name = "DEBUG"; break;
        case CE_LOG_WARNING: log_level_name = "WARNING"; break;
        case CE_LOG_ERROR: log_level_name = "ERROR"; break;
        case CE_LOG_FATAL: log_level_name = "FATAL ERROR"; break;
        default:
            assert(false); break;
        }
        int idx = m_Dialog.LogLevelList->findText(log_level_name);
        assert(idx >= 0);
        m_Dialog.LogLevelList->setCurrentIndex(idx);

        for(size_t i = 0; i < m_SettingsFile.getContextCount(); ++i)
            m_Dialog.ContextsList->addItem(m_SettingsFile.getContext(i).getName().c_str());
    }
    else
    {
        setLoggingLevel(m_Dialog.LogLevelList->currentText());
        m_SettingsFile.setDefaultLogFile();
        m_SettingsFile.setRenderer(m_Dialog.RendererList->currentText().toStdString());
    }
    
    m_Dialog.CtxSettings->hide();
    m_Dialog.DeleteContext->setEnabled(false);
}

void CESettings::on_ButtonBox_accepted()
{
    bool res = m_SettingsFile.save();
    if(!res)
        QMessageBox::critical(this, "Error", "An error has occurred while trying to save the configuration file.");
}

void CESettings::on_AddContext_clicked(bool checked)
{
    size_t idx = 1;
    const size_t num_idx = (sizeof("Context") - 1);
    for(int i = 0; i < m_Dialog.ContextsList->count(); ++i)
    {
        QString current = m_Dialog.ContextsList->item(i)->data(Qt::DisplayRole).toString();
        if(current.indexOf(QRegExp("Context[0-9]+")) == 0)
        {
            size_t val = current.mid(num_idx).toInt();
            idx = std::max(idx, val + 1);
        }
    }       
    QString ctx_name = QString("Context%1").arg(idx);
    m_Dialog.ContextsList->addItem(ctx_name);
    m_SettingsFile.addContext(ctx_name.toStdString());
    ContextSettings& ctx = m_SettingsFile.lastContext();
    ctx.setWidth(800);
    ctx.setHeight(600);
    ctx.setMSAA(1);
}

void CESettings::on_ContextsList_itemSelectionChanged()
{
    QList<QListWidgetItem *> selected = m_Dialog.ContextsList->selectedItems();
    m_Dialog.DeleteContext->setEnabled(!selected.empty());
    m_Dialog.CtxSettings->setVisible(!selected.empty());
    if(!selected.empty())
    {
        ContextSettings& ctx = m_SettingsFile.getContext(selected.front()->data(Qt::DisplayRole).toString().toStdString());
        m_Dialog.MSAA->setValue(ctx.getMSAA());
        m_Dialog.ScreenHeight->setValue(ctx.getHeight());
        m_Dialog.ScreenWidth->setValue(ctx.getWidth());
    }
}

void CESettings::on_MSAA_valueChanged(int i)
{
    QList<QListWidgetItem *> selected = m_Dialog.ContextsList->selectedItems();
    assert(!selected.empty());
    ContextSettings& ctx = m_SettingsFile.getContext(selected.front()->data(Qt::DisplayRole).toString().toStdString());
    ctx.setMSAA(static_cast<size_t>(i));
}
    
void CESettings::on_ScreenHeight_valueChanged(int i)
{
    QList<QListWidgetItem *> selected = m_Dialog.ContextsList->selectedItems();
    assert(!selected.empty());
    ContextSettings& ctx = m_SettingsFile.getContext(selected.front()->data(Qt::DisplayRole).toString().toStdString());
    ctx.setHeight(static_cast<size_t>(i));
}

void CESettings::on_ScreenWidth_valueChanged(int i)
{
    QList<QListWidgetItem *> selected = m_Dialog.ContextsList->selectedItems();
    assert(!selected.empty());
    ContextSettings& ctx = m_SettingsFile.getContext(selected.front()->data(Qt::DisplayRole).toString().toStdString());
    ctx.setWidth(static_cast<size_t>(i));
}

void CESettings::on_DeleteContext_clicked(bool checked)
{
    QList<QListWidgetItem *> selected = m_Dialog.ContextsList->selectedItems();
    assert(!selected.empty());
    m_Dialog.ContextsList->takeItem(m_Dialog.ContextsList->currentRow());
    m_SettingsFile.deleteContext(selected.front()->data(Qt::DisplayRole).toString().toStdString());
}

void CESettings::on_RendererList_currentIndexChanged(const QString& text)
{
    m_SettingsFile.setRenderer(text.toStdString());
}

void CESettings::setLoggingLevel(const QString& log_level_name)
{
    LoggingLevel log_level;
    if(log_level_name == "INFO")
        log_level = CE_LOG_INFO;
    else if(log_level_name == "DEBUG")
        log_level = CE_LOG_DEBUG;
    else if(log_level_name == "WARNING")
        log_level = CE_LOG_WARNING;
    else if(log_level_name == "ERROR")
        log_level = CE_LOG_ERROR;
    else if(log_level_name == "FATAL ERROR")
        log_level = CE_LOG_FATAL;
    else
        assert(!"Unknown logging level");
    m_SettingsFile.setLogLevel(log_level);
}

void CESettings::on_LogLevelList_currentIndexChanged(const QString& log_level_name)
{
    setLoggingLevel(log_level_name);
}

void CESettings::on_AddResBtn_clicked(bool checked)
{
    QString dir = QFileDialog::getExistingDirectory(this, tr("Add Resource"));
    if(dir.isEmpty())
        return;

    QStringList directories;
    directories.push_back(dir);
    m_ResListModel.insertRows(directories);

    m_SettingsFile.addResource(dir.toStdString());
}

void CESettings::on_RemoveResBtn_clicked(bool checked)
{
    QItemSelectionModel* selection_model = m_Dialog.ResourceView->selectionModel();
    QModelIndexList midx_list = selection_model->selectedRows();
    QList<QPersistentModelIndex> pmidx_list;
    for(QModelIndexList::const_iterator i = midx_list.begin(); i != midx_list.end(); ++i)
        pmidx_list.append(QPersistentModelIndex(*i));
    for(QList<QPersistentModelIndex>::iterator i = pmidx_list.begin(); i != pmidx_list.end(); ++i)
    {
        m_SettingsFile.removeResource(m_ResListModel.data(*i, Qt::DisplayRole).toString().toStdString());
        m_ResListModel.removeRow(i->row());
    }
}

void CESettings::on_LogFileBrowseButton_clicked(bool checked)
{
    QString filename = QFileDialog::getSaveFileName(this, tr("Specify log file"), "./", tr("Text files (*.txt)"));
    if(filename == QString::null)
        return;
    m_Dialog.LogFileEdit->setText(filename);
}

void CESettings::on_DefaultLogCheckBox_stateChanged(int state)
{
    bool disable = (state == Qt::Checked);
    m_Dialog.LogFileEdit->setDisabled(disable);
    m_Dialog.LogFileBrowseButton->setDisabled(disable);
    if(disable)
        m_SettingsFile.setDefaultLogFile();
    else
        m_SettingsFile.setLogFile(m_Dialog.LogFileEdit->text().toStdString());
}

//void CESettings::on_MSAA_valueChanged(int val)
//{
//  m_Dialog.MSAA->setValue(val < 2 ? 1 : pow_of_2(val));
//}

ResourceListModel::ResourceListModel(QObject* parent)
    :   QAbstractListModel(parent)
{

}

bool ResourceListModel::insertRows(int position, int rows, const QModelIndex &index)
{
    beginInsertRows(QModelIndex(), position, position+rows-1);
    for(int row = 0; row < rows; ++row)
        m_ResourcePaths.insert(position, "");

    endInsertRows();
    return true;
}

bool ResourceListModel::removeRows(int position, int rows, const QModelIndex &index)
{
    beginRemoveRows(QModelIndex(), position, position+rows-1);
    for(int row = 0; row < rows; ++row)
        m_ResourcePaths.removeAt(position);

    endRemoveRows();
    return true;
}

bool ResourceListModel::insertRows(QStringList paths, int position, const QModelIndex &index)
{
    for(QStringList::iterator i = paths.begin(); i != paths.end(); ++i)
        for(QStringList::iterator j = m_ResourcePaths.begin(); j != m_ResourcePaths.end(); ++j)
            if(*i == *j)
                paths.erase(i);
    if(paths.empty())
        return true;

    beginInsertRows(QModelIndex(), position, position+paths.size()-1);
    for(int i = 0; i < paths.size(); ++i)
        m_ResourcePaths.insert(position, paths[i]);

    endInsertRows();
    return true;
}

int ResourceListModel::rowCount(const QModelIndex& parent) const
{
    return m_ResourcePaths.size();
}

QVariant ResourceListModel::data(const QModelIndex& index, int role) const
{
    return index.isValid() && index.row() < m_ResourcePaths.size() && role == Qt::DisplayRole ? m_ResourcePaths.at(index.row()) : QVariant();
}

void ResourceListModel::data(QStringList& paths) const
{
    paths = m_ResourcePaths;
}

QVariant ResourceListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if(role != Qt::DisplayRole)
        return QVariant();
    return orientation == Qt::Horizontal ? QString("Row") : QString("Column");
}

